using System;
using System.Collections.Generic;
using System.Data.SqlClient;

namespace PropertyExpression.ControllableQuery
{
    public class QueryContext
    {
        private readonly SqlCommand sqlCommand;
        private int sqlParameterIndex;

        public QueryContext(SqlCommand sqlCommand)
        {
            this.sqlCommand = sqlCommand;
        }

        public IParam<Guid> CreateParam(Guid value)
        {
            return new Param<Guid>(this, parameterName => new SqlParameter(parameterName, value));
        }

        public IParam<string> CreateParam(string value)
        {
            return new Param<string>(this, parameterName => new SqlParameter(parameterName, value) { Size = -1 });
        }

        private class Param<T> : IParam<T>
        {
            private readonly QueryContext queryContext;
            private readonly Func<string, SqlParameter> sqlParameterFunc;

            public Param(QueryContext queryContext, Func<string, SqlParameter> sqlParameterFunc)
            {
                this.queryContext = queryContext;
                this.sqlParameterFunc = sqlParameterFunc;
            }

            public ISqlParam<T> GenerateSqlParam()
            {
                return new SqlParam(this);
            }

            private class SqlParam : ISqlParam<T>
            {
                private readonly Param<T> parent;

                public SqlParam(Param<T> parent)
                {
                    this.parent = parent;
                }

                public string ToSql()
                {
                    var parameterName = string.Format("@{0}", parent.queryContext.GetNextSqlParameterName());
                    parent.queryContext.sqlCommand.Parameters.Add(parent.sqlParameterFunc(parameterName));
                    return parameterName;
                }

                public override string ToString()
                {
                    return ToSql();
                }
            }

            public override string ToString()
            {
                return this.ToSql();
            }
        }

        public IParam<IEnumerable<T>> CreateParam<T>(IEnumerable<T> value)
        {
            throw new NotImplementedException();
        }

        private string GetNextSqlParameterName()
        {
            var result = string.Format("p{0}", sqlParameterIndex);
            sqlParameterIndex++;
            return result;
        }
    }
}